1Writer 過去タスク検索 + 複数入力
たまにやるプロジェクトの一連のタスクをリストから選択してパッと追加したりできる
⚠️デイリーノートを順に開いてデータを検索するので、まあまあ時間がかかるしページがバーっと切り替わるのが見えて鬱陶しいかも
code:js
// 過去データ検索
const dayDifference = Math.floor((new Date() - new Date('2024-08-15')) / (1000 * 60 * 60 * 24));
const maxDaysToSearch = dayDifference; // 検索範囲を1ヶ月に制限
const maxTasksToFind = 100; // 検索するタスクの上限を設定
// ノート情報の保存
var cursorPosition = editor.getSelectedRange(); // カーソル位置を保存
const start, end = editor.getSelectedLineRange(); // 現在の選択行の範囲を取得 let originalFilePath; // 元々開いていたファイルのパスを保持
// 検索キーワードを決める(選択範囲があればそれを使用し、なければ入力を求める)
function promptUserForKeywords() {
return new Promise((resolve) => {
const selectedText = editor.getSelectedText(); // 選択されたテキストを取得
if (selectedText) {
resolve(selectedText.split(" ")); // 選択範囲がある場合、そのままキーワードとして使用
} else {
ui.input("タスク検索", "", "検索キーワードを入力してください(スペースで区切るとAND検索)", "default", (input) => {
if (input) {
resolve(input.split(" ")); // スペースで分割してキーワード配列に
} else {
resolve(null); // キャンセルされた場合
}
});
}
});
}
// 指定された日付のノートを開き、その内容を取得する
function getNoteForDate(folderPath, dateString) {
return new Promise((resolve) => {
const filePath = ${folderPath}/${dateString}.md; // 日付ベースのファイル名
editor.openFile(filePath, "edit", (success) => {
if (success) {
const noteText = editor.getText();
resolve(noteText); // ファイルが開けた場合、内容を返す
} else {
resolve(null); // ファイルが開けなかった場合、null を返す
}
});
});
}
// 行がタスクかどうかを判定する関数(タスクは - [x] で始まる)
function isTask(line) {
return line.startsWith("- x "); }
// 行にすべてのキーワードが含まれているかを判定(AND検索)
function containsKeywords(line, keywords) {
return keywords.every(keyword => line.toLowerCase().includes(keyword.toLowerCase()));
}
// 指定フォルダ内でタスクを検索する
async function searchTasks(keywords, folderPath) {
let foundTasks = [];
let currentDate = new Date(); // 現在の日付を取得
let daysChecked = 0;
while (foundTasks.length < maxTasksToFind && daysChecked < maxDaysToSearch) {
// YYYY-MM-DD形式で日付をフォーマット
const dateString = currentDate.toISOString().split('T')0; const note = await getNoteForDate(folderPath, dateString);
if (note) {
const lines = note.split('\n');
for (const line of lines) {
if (isTask(line) && containsKeywords(line, keywords)) {
foundTasks.push({ date: dateString, task: line });
if (foundTasks.length === maxTasksToFind) break;
}
}
}
// 日付を前日に設定
currentDate.setDate(currentDate.getDate() - 1);
daysChecked++;
}
return foundTasks;
}
// タスク行を解析し、開始時刻、終了時刻、実績時間、見積時間、タスク名を抽出する
function parseTaskLine(line) {
const taskRegex = /^- \x\ (\d{2}:\d{2})-(\d{2}:\d{2})(?:\s+(\d+)?\\?(\d+)?\s+)?(.+)$/; const match = line.match(taskRegex);
if (match) {
return {
startTime: match1 || null, // 開始時刻 endTime: match2 || null, // 終了時刻 actualTime: match3 || null, // 実績時間 estimatedTime: match4 || null, // 見積時間 taskName: match5 ? match5.trim() : "不明" // タスク名 };
} else {
return null; // フォーマットが一致しない場合
}
}
// タスクをリスト形式で表示する
function displayTasks(tasks) {
if (tasks.length === 0) {
ui.hudError("該当するタスクが見つかりませんでした。");
} else {
const taskList = tasks.map(task => {
const parsedTask = parseTaskLine(task.task);
if (parsedTask) {
const title = ${parsedTask.taskName};
const value = \\${parsedTask.actualTime} ${parsedTask.taskName};
let subtitleParts = [${task.date} ];
if (parsedTask.startTime && parsedTask.endTime) {
subtitleParts.push(${parsedTask.startTime}-${parsedTask.endTime});
}
if (parsedTask.actualTime || parsedTask.estimatedTime) {
subtitleParts.push(' (');
}
if (parsedTask.actualTime) {
subtitleParts.push(${parsedTask.actualTime});
}
if (parsedTask.actualTime || parsedTask.estimatedTime) {
subtitleParts.push(')');
}
const subtitle = subtitleParts.join('');
return { title, subtitle, value };
} else {
return { title: 不明, subtitle: ${task.date}, value: - }; // 解析できない場合
}
});
ui.list("検索結果", taskList.map(t => ${t.title}|${t.value}|${t.subtitle}), true, (selectedTasks) => {
if (selectedTasks) {
// 選択されたタスクをすべて挿入
const tasksToInsert = selectedTasks.join('\n');
editor.openFile(originalFilePath, 'edit', function () {
editor.setSelectedRange(cursorPosition0); // カーソル位置に戻る editor.replaceSelection(${tasksToInsert}\n); // 選択されたすべてのタスクを挿入
editor.setSelectedRange(cursorPosition0 + tasksToInsert.length); // カーソルを挿入後の位置に移動 });
ui.hudSuccess(選択されたタスクが挿入されました。);
}
});
}
}
// 元々開いていたファイルを再度開く
function reopenOriginalFile() {
if (originalFilePath) {
editor.openFile(originalFilePath, "edit", (success) => {
if (!success) {
ui.hudError("元のファイルを開けませんでした。");
}
});
}
}
// メイン処理
async function main() {
const folderPath = editor.getFolderPath(); // パスを確認して指定する
const filePath = editor.getFileName();
originalFilePath = folderPath + "/" + filePath; // 現在開いているファイルを保存
const keywords = await promptUserForKeywords();
if (!keywords) {
ui.hudError("検索キーワードが入力されませんでした。");
return;
}
const tasks = await searchTasks(keywords, folderPath); // タスクを検索
displayTasks(tasks); // 結果を表示
reopenOriginalFile();
}
// 実行
main();